package com.powermgr.boringtest.service.impl;

import com.alibaba.fastjson.JSON;
import com.powermgr.boringtest.bean.PrData;
import com.powermgr.boringtest.bean.Device;
import com.powermgr.boringtest.result.Result;
import com.powermgr.boringtest.service.*;
import com.powermgr.boringtest.task.impl.*;
import com.powermgr.boringtest.utils.*;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

import static com.powermgr.boringtest.utils.ConfigUtils.*;

/**
 * StartServiceImpl
 *
 * @author qiuxiangdong
 * @date 2023/6/12
 */
@Log4j2
@Service
public class StartServiceImpl implements IStartService {
    @Resource
    private IVisitService accessService;
    @Resource
    private IDeviceService deviceService;
    @Resource
    private IPrService prService;
    //等待队列
    private final BlockingQueue<PrData> waitQueue = new LinkedBlockingQueue<>();
    // 下载队列
    private final BlockingQueue<PrData> downloadQueue = new LinkedBlockingQueue<>();
    //下载队列中的暂停队列
    private final BlockingQueue<PrData> pauseQueue = new LinkedBlockingQueue<>();
    // 刷机执行队列
    private final BlockingQueue<PrData> flashQueue = new LinkedBlockingQueue<>();
    // 已执行完成队列
    private final BlockingQueue<PrData> completeQueue = new LinkedBlockingQueue<>();
    ExecutorService executorService;

    @PostConstruct
    private void init() {
        executorService = Executors.newFixedThreadPool(deviceService.getDeviceNums());
    }
    @PreDestroy
    private void shutdown() {
        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            executorService.shutdownNow();
        }
    }
    @Override
    public Result<Object> getList() {
        List<PrData> list = new ArrayList<>(waitQueue);
        list.addAll(new ArrayList<>(pauseQueue));
        list.addAll(new ArrayList<>(downloadQueue));
        list.addAll(new ArrayList<>(flashQueue));
        if (!PR_FILE_FLAGS) {
            List<PrData> maps = null;
            try {
                maps = ReadWriteUtils.readArchivePrFile();
                log.info("查询 prMaps 信息");
            } catch (IOException e) {
                log.info("初始化 prMaps 失败");
            }
            if (maps != null) {
                for (PrData s : maps) {
                    boolean offer = completeQueue.offer(s);
                }
                list.addAll(maps);
            }
            PR_FILE_FLAGS = true;
        } else {
            list.addAll(new ArrayList<>(completeQueue));
        }
        return Result.success("success", list);
    }

    @Override
    public Result<Object> start(PrData data) {
        if (data.getType().isEmpty()) {
            return Result.failure("请输入测试类型", "{}");
        }
        if (TypeUtils.IsDcts(data.getType())) {
            return Result.failure("暂不支持DCTS类型用例", "{}");
        }
        if (data.getModule().isEmpty()) {
            return Result.failure("请输入模块", "{}");
        }
        Result<Object> exist = isExist(data.getType(), data.getModule());
        if (exist.isError()) {
            return exist;
        }
        Result<Object> getPrVersion = prService.getPrVersion(data.getBranch(), data.getPrUrl());
        String version_url = (String) getPrVersion.getData();
        if (version_url.contains("tar.gz")) {
            data.setVersion_url(version_url);
            data.setVersion_name(FileZipUtils.uuidVersion());
        } else {
            return getPrVersion;
        }
        Result<Object> getPrXts = prService.getPrXts(data.getBranch(), data.getPrUrl());
        String xts_url = (String) getPrXts.getData();
        if (xts_url.contains("tar.gz")) {
            data.setXts_url(xts_url);
            data.setXts_name(FileZipUtils.uuidXTS());
        }
        Result<Object> getPrTdd = prService.getPrTdd(data.getBranch(), data.getPrUrl());
        String tdd_url = (String) getPrTdd.getData();
        if (tdd_url.contains("tar.gz")) {
            data.setTdd_url(tdd_url);
            data.setTdd_name(FileZipUtils.uuidTDD());
        }
        String[] user = data.getEmail().split("@");
        data.setUser(user[0]);
        data.setCreat_time(ReadWriteUtils.getPrTime());
        data.setBegin_time("未开始");
        data.setSn_id("等待设备");
        data.setReports_name(FileZipUtils.uuidReportsName());
        data.setState("0");
        if (TypeUtils.IsXTS(data.getType()) && data.getXts_url().isEmpty() && !data.getBranch().equals("master")) {
            return Result.failure("您的选择中包含了XTS相关用例，但Pr编译结果中没有 dayu200_xts，请重新选择", null);
        }
        if (TypeUtils.IsTDD(data.getType()) && data.getTdd_url().isEmpty() && !data.getBranch().equals("master")) {
            return Result.failure("您的选择中包含了TDD相关用例，但Pr编译结果中没有 dayu200_tdd，请重新选择", null);
        }
        if (waitQueue.offer(data)) {
            executorService.execute(new Consumer());
            if (TypeUtils.IsXTS(data.getType()) && data.getXts_url().isEmpty()) {
                return Result.success("您的选择中包含了XTS相关用例，但Pr编译结果中没有 dayu200_xts，为您选取今天2点的XTS用例执行", null);
            }
            if (TypeUtils.IsTDD(data.getType()) && data.getTdd_url().isEmpty()) {
                return Result.failure("您的选择中包含了相关用例，但Pr编译结果中没有 dayu200_tdd，为您选取今天2点的TDD用例执行", null);
            }
            return Result.success("该PR已经编译成功，为你从PR中获取版本执行测试用例，稍后将结果发送至你的邮箱。", null);
        }
        return Result.failure("该PR添加失败", null);
    }
    private PrData queryNowList(String version) {
        List<PrData> lists = new ArrayList<>(new ArrayList<>(downloadQueue));
        for (PrData map : lists) {
            if (map.getVersion_url().equals(version)) {
                return map;
            }
        }
        return null;
    }
    private PrData queryList(String version) {
        List<PrData> lists = new ArrayList<>();
        lists.addAll(new ArrayList<>(flashQueue));
        lists.addAll(new ArrayList<>(completeQueue));
        for (PrData map : lists) {
            if (map.getVersion_url().equals(version)) {
                log.info("所选pr的版本用例已经下载过");
                return map;
            }
        }
        log.info("此pr版本下载地址未被下载过");
        return null;
    }
    class Consumer implements Runnable {
        @Override
        public void run() {
            Optional<Device> idleDevice = deviceService.findIdleDevice();
            while (idleDevice.isPresent()) {
                try {
                    TaskHandler<PrData> handler = new TaskHandler<>();
                    Device device = idleDevice.get();
                    String sn = device.getSn();
                    deviceService.setDeviceBusy(sn);
                    PrData prData = waitQueue.take();
                    prData.setSn_id(sn);
                    prData.setDevice(device);
                    log.info("SN- " + sn + ": " + " ==========开始执行==========");
                    log.info("SN- " + sn + ": " + "当前TableData：" + prData);
                    prData.setBegin_time(ReadWriteUtils.getPrTime());
                    removeOnce(sn);
                    if (pauseQueue.offer(prData)){
                        if (queryNowList(prData.getVersion_url()) != null){
                            log.info("SN- " + prData.getSn_id() + ": 当前有同一pr在下载版本和用例，等待第一个下载完成后执行！");
                            boolean isRunning = true;
                            while (isRunning) {
                                try {
                                    if (queryNowList(prData.getVersion_url()) == null){
                                        isRunning = false;
                                    }
                                    Thread.sleep(10000);
                                } catch (InterruptedException e) {
                                    log.error(e);
                                }
                            }
                            log.info("SN- " + prData.getSn_id() + ": 第一个下载版本和用例完成，继续执行！");
                        }
                    }
                    if (downloadQueue.offer(pauseQueue.take())){
                        PrData oldPrData= queryList(prData.getVersion_url());
                        if (oldPrData != null){
                            prData.setVersion_name(oldPrData.getVersion_name());
                            prData.setXts_name(oldPrData.getXts_name());
                            prData.setTdd_name(oldPrData.getTdd_name());
                            if (!handler.executeTask(new DownLoadOldPrTask(), prData)){
                                completeQueue.offer(downloadQueue.take());
                                storingLosers(prData);
                                return;
                            }
                        } else {
                            if (!handler.executeTask(new DownloadNewPrTask(), prData)){
                                completeQueue.offer(downloadQueue.take());
                                storingLosers(prData);
                                return;
                            }
                        }
                    }
                    if (flashQueue.offer(downloadQueue.take())){
                        if (!handler.executeTask(new FlashDevicePrTask(), prData)){
                            completeQueue.offer(flashQueue.take());
                            storingLosers(prData);
                            return;
                        }
                        if (!handler.executeTask(new RunTestCasesPrTask(), prData)){
                            completeQueue.offer(flashQueue.take());
                            storingLosers(prData);
                            return;
                        }
                    }
                    updateModuleType(prData);
                    if (completeQueue.offer(flashQueue.take())){
                        prData.setEnd_time(ReadWriteUtils.getPrTime());
                        FileZipUtils.ToZip(prData.getReports_name(), prData.getSn_id());
                        prData.setTest("下载");
                        prData.setReports_url("download?reports=" + prData.getReports_name());
                        accessService.incrementAnalyze();
                        String prDataStr = JSON.toJSONString(prData);
                        ReadWriteUtils.writeFile(PR_3DAY + File.separator + ReadWriteUtils.getCurrentTime() + ".json", prDataStr);
                    }
                    log.info("SN- " + prData.getSn_id() + ": " + " ==========结束==========");
                    deviceService.setDeviceIdle(sn);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
    private Result<Object> isExist(List<String> prType, List<String> prModule) {
        StringBuilder no_case = new StringBuilder();
        for (String module : prModule) {
            for (String type : prType) {
                if (InitUtils.getCaseValue(type, module) == null){
                    no_case.append(module).append("不存在").append(type).append("用例、");
                }
            }
        }
        if (no_case.toString().isEmpty()){
            return Result.success("success",null);
        }
        log.error("-----" + no_case);
        return Result.failure( no_case.toString(),null);
    }

    private void removeOnce(String sn){
        log.info("*清理上一次执行遗留文件");
        FileZipUtils.deleteFile(SN + File.separator + sn +  File.separator + "pr");
        FileZipUtils.createFile(SN + File.separator + sn +  File.separator + "pr" + File.separator + "version");
        FileZipUtils.createFile(SN + File.separator + sn +  File.separator + "pr" + File.separator + "xts");
        FileZipUtils.createFile(SN + File.separator + sn +  File.separator + "pr" + File.separator + "tdd");
        FileZipUtils.deleteFile(SN + File.separator + sn +  File.separator + "case" +  File.separator + "acts" + File.separator + "reports");
        FileZipUtils.createFile(SN + File.separator + sn +  File.separator + "case" +  File.separator + "acts" + File.separator + "reports");
        FileZipUtils.deleteFile(SN + File.separator + sn +  File.separator + "case" +  File.separator + "hats" + File.separator + "reports");
        FileZipUtils.createFile(SN + File.separator + sn +  File.separator + "case" +  File.separator + "hats" + File.separator + "reports");
        FileZipUtils.deleteFile(SN + File.separator + sn +  File.separator + "case" +  File.separator + "dcts" + File.separator + "reports");
        FileZipUtils.createFile(SN + File.separator + sn +  File.separator + "case" +  File.separator + "dcts" + File.separator + "reports");
        FileZipUtils.deleteFile(SN + File.separator + sn +  File.separator + "case" +  File.separator + "developertest" + File.separator + "reports");
        FileZipUtils.createFile(SN + File.separator + sn +  File.separator + "case" +  File.separator + "developertest" + File.separator + "reports");
        log.info("*清理上一次执行遗留文件完成");
    }

    private void updateModuleType(PrData prData){
        List<String> module = prData.getModule();
        if (module.size() > 1){
            List<String> updatedModule = module.stream()
                    .map(i ->  i + " ")
                    .collect(Collectors.toList());
            prData.setModule(updatedModule);
        }
        List<String> type = prData.getType();
        if (type.size() > 1){
            List<String> updatedType = type.stream()
                    .map(i ->  i + " ")
                    .collect(Collectors.toList());
            prData.setType(updatedType);
        }
    }
    private void storingLosers(PrData prData) throws IOException {
        deviceService.setDeviceIdle(prData.getSn_id());
        prData.setEnd_time(ReadWriteUtils.getPrTime());
        prData.setTest("无");
        accessService.incrementAnalyze();
        String prDataStr = JSON.toJSONString(prData);
        ReadWriteUtils.writeFile(PR_3DAY + File.separator + ReadWriteUtils.getCurrentTime() + ".json", prDataStr);
    }
}

